/*
 * Copyright 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
@file:JvmName("ComposeRuntimeFlags")

package androidx.compose.ui

import androidx.compose.ui.node.findNearestAncestor
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName

/**
 * This is a collection of flags which are used to guard against regressions in some of the
 * "riskier" refactors or new feature support that is added to this module. These flags are always
 * "on" in the published artifact of this module, however these flags allow end consumers of this
 * module to toggle them "off" in case this new path is causing a regression.
 *
 * These flags are considered temporary, and there should be no expectation for these flags be
 * around for an extended period of time. If you have a regression that one of these flags fixes, it
 * is strongly encouraged for you to file a bug ASAP.
 *
 * **Usage:**
 *
 * In order to turn a feature off in a debug environment, it is recommended to set this to false in
 * as close to the initial loading of the application as possible. Changing this value after compose
 * library code has already been loaded can result in undefined behavior.
 *
 *      class MyApplication : Application() {
 *          override fun onCreate() {
 *              ComposeUiFlags.SomeFeatureEnabled = false
 *              super.onCreate()
 *          }
 *      }
 *
 * In order to turn this off in a release environment, it is recommended to additionally utilize R8
 * rules which force a single value for the entire build artifact. This can result in the new code
 * paths being completely removed from the artifact, which can often have nontrivial positive
 * performance impact.
 *
 *      -assumevalues class androidx.compose.ui.ComposeUiFlags {
 *          public static int isRectTrackingEnabled return false
 *      }
 */
@ExperimentalComposeUiApi
object ComposeUiFlags {
    /**
     * This enables fixes for View focus. The changes are large enough to require a flag to allow
     * disabling them.
     */
    @field:Suppress("MutableBareField") @JvmField var isViewFocusFixEnabled: Boolean = false

    /**
     * This flag enables an alternate approach to fixing the issues addressed by the
     * [isViewFocusFixEnabled] flag.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isBypassUnfocusableComposeViewEnabled: Boolean = true

    /**
     * This flag enables a fix for b/378570682. For API >=26. We attempt to manually find the next
     * focusable item for 1-D focus search cases when Compose does not have any focusable content.
     */
    @field:Suppress("MutableBareField") @JvmField var isPre26FocusFinderFixEnabled: Boolean = false

    /**
     * This flag enables a fix for b/388590015. The view system ignores an invalid prevFocusRect
     * when requestFocus is called, so we support this behavior in Compose too.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isIgnoreInvalidPrevFocusRectEnabled: Boolean = true

    /**
     * When an embedded view that is focused is removed from the hierarchy, it triggers a
     * requestFocus() which tries to re-assign focus before the previous composition is complete.
     * This flag enables a fix for this issue.
     */
    @Deprecated("This flag is no longer needed.")
    @field:Suppress("MutableBareField", "unused")
    @JvmField
    var isRemoveFocusedViewFixEnabled: Boolean = false

    /**
     * Enable WindowInsets rulers:
     * * `SystemBarsRulers`
     * * `ImeRulers`
     * * `StatusBarsRulers`
     * * `NavigationBarsRulers`
     * * `CaptionBarRulers`
     * * `MandatorySystemGesturesRulers`
     * * `TappableElementRulers`
     * * `WaterfallRulers`
     * * `SafeDrawingRulers`
     * * `SafeGesturesRulers`
     * * `SafeContentRulers`
     */
    // off for b/410868572
    @field:Suppress("MutableBareField") @JvmField var areWindowInsetsRulersEnabled = true

    /** Enable initial focus when a focusable is added to a screen with no focusable content. */
    @field:Suppress("MutableBareField")
    @JvmField
    var isInitialFocusOnFocusableAvailable: Boolean = false

    /**
     * With this flag on, requesting focus on a non-focusable focus target will request focus for
     * one of its children, which makes
     * [FocusTargetModifierNode.requestFocus][androidx.compose.ui.focus.FocusTargetModifierNode.requestFocus]
     * consistent with
     * [FocusRequester.requestFocus][androidx.compose.ui.focus.FocusRequester.requestFocus] and
     * [FocusRequesterModifierNode.requestFocus][androidx.compose.ui.focus.requestFocus]
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isRequestFocusOnNonFocusableFocusTargetEnabled: Boolean = true

    /**
     * With this flag on, the adaptive refresh rate (ARR) feature will be enabled. A preferred frame
     * rate can be set on a Composable through frame rate modifier: [Modifier.preferredFrameRate]
     */
    @field:Suppress("MutableBareField") @JvmField var isAdaptiveRefreshRateEnabled: Boolean = true

    /** Flag for enabling indirect pointer event navigation gestures in Compose. */
    @field:Suppress("MutableBareField")
    @JvmField
    var isIndirectPointerNavigationGestureDetectorEnabled: Boolean = true

    /** Flag enables optimized focus change dispatching logic. */
    @field:Suppress("MutableBareField")
    @JvmField
    var isOptimizedFocusEventDispatchEnabled: Boolean = true

    /** This flag enables setting the shape semantics property in the graphicsLayer modifiers. */
    @field:Suppress("MutableBareField")
    @JvmField
    var isGraphicsLayerShapeSemanticsEnabled: Boolean = true

    /**
     * Enable fix to scroll target rect to the center when performing scroll capture, thus generally
     * avoiding floating content at the top and bottom of the UI.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isScrollCaptureCenteringEnabled: Boolean = true

    /**
     * Enable performance optimization where coordinates calculations like
     * [androidx.compose.ui.layout.LayoutCoordinates.localToRoot] are using the cached offsets we
     * already have in RectManager, instead of traversing the whole tree on each call.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isRectManagerOffsetUsageFromLayoutCoordinatesEnabled: Boolean = true

    /**
     * Enables automatic pinning of interop AndroidViews when they are focused inside lazy
     * containers.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isPinningFocusedAndroidViewsEnabled: Boolean = true

    /**
     * Enables a fix where [TraversableNode] traversal method [findNearestAncestor] will take into
     * consideration any delegates that might also be traversable.
     */
    @field:Suppress("MutableBareField")
    @JvmField
    var isTraversableDelegatesFixEnabled: Boolean = true
}
